{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "1be69f0e-bc9c-41c1-ba7b-c5b9a42c2e7e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting sentence-transformers\n",
      "  Using cached sentence_transformers-2.2.2-py3-none-any.whl\n",
      "Collecting transformers<5.0.0,>=4.6.0 (from sentence-transformers)\n",
      "  Downloading transformers-4.31.0-py3-none-any.whl (7.4 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m7.4/7.4 MB\u001b[0m \u001b[31m22.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: tqdm in /opt/conda/lib/python3.10/site-packages (from sentence-transformers) (4.65.0)\n",
      "Requirement already satisfied: torch>=1.6.0 in /opt/conda/lib/python3.10/site-packages (from sentence-transformers) (2.0.0)\n",
      "Requirement already satisfied: torchvision in /opt/conda/lib/python3.10/site-packages (from sentence-transformers) (0.15.1)\n",
      "Requirement already satisfied: numpy in /opt/conda/lib/python3.10/site-packages (from sentence-transformers) (1.23.5)\n",
      "Requirement already satisfied: scikit-learn in /opt/conda/lib/python3.10/site-packages (from sentence-transformers) (1.2.2)\n",
      "Requirement already satisfied: scipy in /opt/conda/lib/python3.10/site-packages (from sentence-transformers) (1.10.1)\n",
      "Collecting nltk (from sentence-transformers)\n",
      "  Using cached nltk-3.8.1-py3-none-any.whl (1.5 MB)\n",
      "Collecting sentencepiece (from sentence-transformers)\n",
      "  Using cached sentencepiece-0.1.99-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB)\n",
      "Collecting huggingface-hub>=0.4.0 (from sentence-transformers)\n",
      "  Using cached huggingface_hub-0.16.4-py3-none-any.whl (268 kB)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from huggingface-hub>=0.4.0->sentence-transformers) (3.12.0)\n",
      "Requirement already satisfied: fsspec in /opt/conda/lib/python3.10/site-packages (from huggingface-hub>=0.4.0->sentence-transformers) (2023.5.0)\n",
      "Requirement already satisfied: requests in /opt/conda/lib/python3.10/site-packages (from huggingface-hub>=0.4.0->sentence-transformers) (2.28.2)\n",
      "Requirement already satisfied: pyyaml>=5.1 in /opt/conda/lib/python3.10/site-packages (from huggingface-hub>=0.4.0->sentence-transformers) (5.4.1)\n",
      "Requirement already satisfied: typing-extensions>=3.7.4.3 in /opt/conda/lib/python3.10/site-packages (from huggingface-hub>=0.4.0->sentence-transformers) (4.5.0)\n",
      "Requirement already satisfied: packaging>=20.9 in /opt/conda/lib/python3.10/site-packages (from huggingface-hub>=0.4.0->sentence-transformers) (23.1)\n",
      "Requirement already satisfied: sympy in /opt/conda/lib/python3.10/site-packages (from torch>=1.6.0->sentence-transformers) (1.11.1)\n",
      "Requirement already satisfied: networkx in /opt/conda/lib/python3.10/site-packages (from torch>=1.6.0->sentence-transformers) (3.1)\n",
      "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6.0->sentence-transformers) (3.1.2)\n",
      "Collecting regex!=2019.12.17 (from transformers<5.0.0,>=4.6.0->sentence-transformers)\n",
      "  Using cached regex-2023.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (770 kB)\n",
      "Collecting tokenizers!=0.11.3,<0.14,>=0.11.1 (from transformers<5.0.0,>=4.6.0->sentence-transformers)\n",
      "  Using cached tokenizers-0.13.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.8 MB)\n",
      "Collecting safetensors>=0.3.1 (from transformers<5.0.0,>=4.6.0->sentence-transformers)\n",
      "  Using cached safetensors-0.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB)\n",
      "Requirement already satisfied: click in /opt/conda/lib/python3.10/site-packages (from nltk->sentence-transformers) (8.1.3)\n",
      "Requirement already satisfied: joblib in /opt/conda/lib/python3.10/site-packages (from nltk->sentence-transformers) (1.2.0)\n",
      "Requirement already satisfied: threadpoolctl>=2.0.0 in /opt/conda/lib/python3.10/site-packages (from scikit-learn->sentence-transformers) (3.1.0)\n",
      "Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in /opt/conda/lib/python3.10/site-packages (from torchvision->sentence-transformers) (9.4.0)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.10/site-packages (from jinja2->torch>=1.6.0->sentence-transformers) (2.1.2)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /opt/conda/lib/python3.10/site-packages (from requests->huggingface-hub>=0.4.0->sentence-transformers) (3.1.0)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.10/site-packages (from requests->huggingface-hub>=0.4.0->sentence-transformers) (3.4)\n",
      "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /opt/conda/lib/python3.10/site-packages (from requests->huggingface-hub>=0.4.0->sentence-transformers) (1.26.15)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.10/site-packages (from requests->huggingface-hub>=0.4.0->sentence-transformers) (2023.5.7)\n",
      "Requirement already satisfied: mpmath>=0.19 in /opt/conda/lib/python3.10/site-packages (from sympy->torch>=1.6.0->sentence-transformers) (1.3.0)\n",
      "Installing collected packages: tokenizers, sentencepiece, safetensors, regex, nltk, huggingface-hub, transformers, sentence-transformers\n",
      "Successfully installed huggingface-hub-0.16.4 nltk-3.8.1 regex-2023.6.3 safetensors-0.3.1 sentence-transformers-2.2.2 sentencepiece-0.1.99 tokenizers-0.13.3 transformers-4.31.0\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.1.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.2.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "!pip install sentence-transformers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "736dc101-5863-44ff-b086-a25a69f0b51d",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: datasets in /opt/conda/lib/python3.10/site-packages (2.14.1)\n",
      "Requirement already satisfied: numpy>=1.17 in /opt/conda/lib/python3.10/site-packages (from datasets) (1.23.5)\n",
      "Requirement already satisfied: pyarrow>=8.0.0 in /opt/conda/lib/python3.10/site-packages (from datasets) (12.0.0)\n",
      "Requirement already satisfied: dill<0.3.8,>=0.3.0 in /opt/conda/lib/python3.10/site-packages (from datasets) (0.3.6)\n",
      "Requirement already satisfied: pandas in /opt/conda/lib/python3.10/site-packages (from datasets) (2.0.1)\n",
      "Requirement already satisfied: requests>=2.19.0 in /opt/conda/lib/python3.10/site-packages (from datasets) (2.28.2)\n",
      "Requirement already satisfied: tqdm>=4.62.1 in /opt/conda/lib/python3.10/site-packages (from datasets) (4.65.0)\n",
      "Requirement already satisfied: xxhash in /opt/conda/lib/python3.10/site-packages (from datasets) (3.3.0)\n",
      "Requirement already satisfied: multiprocess in /opt/conda/lib/python3.10/site-packages (from datasets) (0.70.14)\n",
      "Requirement already satisfied: fsspec[http]>=2021.11.1 in /opt/conda/lib/python3.10/site-packages (from datasets) (2023.5.0)\n",
      "Requirement already satisfied: aiohttp in /opt/conda/lib/python3.10/site-packages (from datasets) (3.8.5)\n",
      "Requirement already satisfied: huggingface-hub<1.0.0,>=0.14.0 in /opt/conda/lib/python3.10/site-packages (from datasets) (0.16.4)\n",
      "Requirement already satisfied: packaging in /opt/conda/lib/python3.10/site-packages (from datasets) (23.1)\n",
      "Requirement already satisfied: pyyaml>=5.1 in /opt/conda/lib/python3.10/site-packages (from datasets) (5.4.1)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /opt/conda/lib/python3.10/site-packages (from aiohttp->datasets) (22.2.0)\n",
      "Requirement already satisfied: charset-normalizer<4.0,>=2.0 in /opt/conda/lib/python3.10/site-packages (from aiohttp->datasets) (3.1.0)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /opt/conda/lib/python3.10/site-packages (from aiohttp->datasets) (6.0.4)\n",
      "Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in /opt/conda/lib/python3.10/site-packages (from aiohttp->datasets) (4.0.2)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /opt/conda/lib/python3.10/site-packages (from aiohttp->datasets) (1.9.2)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /opt/conda/lib/python3.10/site-packages (from aiohttp->datasets) (1.4.0)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /opt/conda/lib/python3.10/site-packages (from aiohttp->datasets) (1.3.1)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from huggingface-hub<1.0.0,>=0.14.0->datasets) (3.12.0)\n",
      "Requirement already satisfied: typing-extensions>=3.7.4.3 in /opt/conda/lib/python3.10/site-packages (from huggingface-hub<1.0.0,>=0.14.0->datasets) (4.5.0)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.10/site-packages (from requests>=2.19.0->datasets) (3.4)\n",
      "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /opt/conda/lib/python3.10/site-packages (from requests>=2.19.0->datasets) (1.26.15)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.10/site-packages (from requests>=2.19.0->datasets) (2023.5.7)\n",
      "Requirement already satisfied: python-dateutil>=2.8.2 in /opt/conda/lib/python3.10/site-packages (from pandas->datasets) (2.8.2)\n",
      "Requirement already satisfied: pytz>=2020.1 in /opt/conda/lib/python3.10/site-packages (from pandas->datasets) (2023.3)\n",
      "Requirement already satisfied: tzdata>=2022.1 in /opt/conda/lib/python3.10/site-packages (from pandas->datasets) (2023.3)\n",
      "Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.10/site-packages (from python-dateutil>=2.8.2->pandas->datasets) (1.16.0)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.1.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.2.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
      "Requirement already satisfied: accelerate in /opt/conda/lib/python3.10/site-packages (0.19.0)\n",
      "Collecting accelerate\n",
      "  Using cached accelerate-0.21.0-py3-none-any.whl (244 kB)\n",
      "Requirement already satisfied: numpy>=1.17 in /opt/conda/lib/python3.10/site-packages (from accelerate) (1.23.5)\n",
      "Requirement already satisfied: packaging>=20.0 in /opt/conda/lib/python3.10/site-packages (from accelerate) (23.1)\n",
      "Requirement already satisfied: psutil in /opt/conda/lib/python3.10/site-packages (from accelerate) (5.9.5)\n",
      "Requirement already satisfied: pyyaml in /opt/conda/lib/python3.10/site-packages (from accelerate) (5.4.1)\n",
      "Requirement already satisfied: torch>=1.10.0 in /opt/conda/lib/python3.10/site-packages (from accelerate) (2.0.0)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from torch>=1.10.0->accelerate) (3.12.0)\n",
      "Requirement already satisfied: typing-extensions in /opt/conda/lib/python3.10/site-packages (from torch>=1.10.0->accelerate) (4.5.0)\n",
      "Requirement already satisfied: sympy in /opt/conda/lib/python3.10/site-packages (from torch>=1.10.0->accelerate) (1.11.1)\n",
      "Requirement already satisfied: networkx in /opt/conda/lib/python3.10/site-packages (from torch>=1.10.0->accelerate) (3.1)\n",
      "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.10/site-packages (from torch>=1.10.0->accelerate) (3.1.2)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.10/site-packages (from jinja2->torch>=1.10.0->accelerate) (2.1.2)\n",
      "Requirement already satisfied: mpmath>=0.19 in /opt/conda/lib/python3.10/site-packages (from sympy->torch>=1.10.0->accelerate) (1.3.0)\n",
      "Installing collected packages: accelerate\n",
      "  Attempting uninstall: accelerate\n",
      "    Found existing installation: accelerate 0.19.0\n",
      "    Uninstalling accelerate-0.19.0:\n",
      "      Successfully uninstalled accelerate-0.19.0\n",
      "Successfully installed accelerate-0.21.0\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.1.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.2.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "!pip install datasets\n",
    "!pip install  accelerate -U "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b59b9525-038f-4820-9d22-1de0d83bfbf7",
   "metadata": {},
   "source": [
    "# finetune 模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "9c2ae124-2a55-4713-afe0-c40be9b3bb5f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sentence_transformers import SentenceTransformer, LoggingHandler\n",
    "from datasets import load_dataset\n",
    "from sentence_transformers import InputExample\n",
    "from torch.utils.data import DataLoader\n",
    "from sentence_transformers import losses\n",
    "import torch\n",
    "import logging"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "07bc65f6-c9a2-47bc-a2da-094b8924ca15",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "logging.basicConfig(format='%(asctime)s - %(message)s', datefmt = '%Y-%m-%d %H:%M:S', level=logging.INFO, handlers =[LoggingHandler()] )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e2e9e75-5fdf-4e85-967f-e4d86f85902a",
   "metadata": {},
   "source": [
    "## 从hf加载模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "id": "66eade76-c737-4abc-8a2d-625347306f2c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2023-07-31 09:31:S - Load pretrained SentenceTransformer: sentence-transformers/paraphrase-multilingual-mpnet-base-v2\n",
      "2023-07-31 09:31:S - Use pytorch device: cuda\n"
     ]
    }
   ],
   "source": [
    "modelB = SentenceTransformer('sentence-transformers/paraphrase-multilingual-mpnet-base-v2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4e5cf155-2608-4cad-934f-c7281e3c8fce",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# dataset_id = \"embedding-data/sentence-compression\"\n",
    "# dataset = load_dataset(dataset_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "fcfa89a5-e6af-45fa-9b76-7b05900aabbb",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['3_faq.faq', '.ipynb_checkpoints', '1_faq.faq', '4_faq.faq', '2_faq.faq']"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import os,datasets\n",
    "filenames = os.listdir('topwar_faq')\n",
    "filenames"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "5808a2dd-569a-4513-9ded-3c25b35a64c9",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "data size:126\n"
     ]
    }
   ],
   "source": [
    "def parse_faq(file_content,QA_SEP='====='):\n",
    "    arr = file_content.split(QA_SEP)\n",
    "    list_arr = []\n",
    "    for item in arr:\n",
    "        question, answer = item.strip().split(\"\\n\", 1)\n",
    "        question = question.replace(\"Question: \", \"\")\n",
    "        answer = answer.replace(\"Answer: \", \"\")\n",
    "        list_arr.append((answer,question))\n",
    "    return list_arr\n",
    "\n",
    "all_datas = []\n",
    "for fn in filenames:\n",
    "    if fn == '.ipynb_checkpoints':\n",
    "        continue\n",
    "    with open(f\"topwar_faq/{fn}\") as f:\n",
    "        data = f.read()\n",
    "        all_datas += parse_faq(data)\n",
    "print(f\"data size:{len(all_datas)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "id": "bd320373-d31a-4258-a2b3-34a7a22fc44c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import pickle\n",
    "all_datas = []\n",
    "with open('topwar_faq/jiangyu.pkl', 'rb') as f:\n",
    "    all_datas = pickle.load(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "id": "c9728729-dece-4933-9a48-fb3dac684a07",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2389"
      ]
     },
     "execution_count": 138,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(all_datas)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 141,
   "id": "734c79a3-92b1-4740-909e-e7e195099bf6",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_examples = []\n",
    "\n",
    "for i in range(len(all_datas)):\n",
    "    example = all_datas[i]\n",
    "    train_examples.append(InputExample(texts=[example[0], example[1]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 142,
   "id": "95c874f8-1f0c-40d9-b9b3-6d4a219646fe",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "\n",
    "train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=64)\n",
    "train_loss = losses.MultipleNegativesRankingLoss(model=modelB)\n",
    "num_epochs = 5\n",
    "warmup_steps = int(len(train_dataloader) * num_epochs * 0.1) #10% of train data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "id": "7353170e-a8af-494b-8981-40f586446955",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Epoch:   0%|          | 0/5 [00:00<?, ?it/s]\n",
      "Iteration:   0%|          | 0/38 [00:00<?, ?it/s]\u001b[A\n",
      "Iteration:   3%|▎         | 1/38 [00:01<00:50,  1.38s/it]\u001b[A\n",
      "Iteration:   5%|▌         | 2/38 [00:02<00:51,  1.43s/it]\u001b[A\n",
      "Iteration:   8%|▊         | 3/38 [00:04<00:50,  1.44s/it]\u001b[A\n",
      "Iteration:  11%|█         | 4/38 [00:05<00:49,  1.45s/it]\u001b[A\n",
      "Iteration:  13%|█▎        | 5/38 [00:07<00:48,  1.46s/it]\u001b[A\n",
      "Iteration:  16%|█▌        | 6/38 [00:08<00:46,  1.46s/it]\u001b[A\n",
      "Iteration:  18%|█▊        | 7/38 [00:10<00:45,  1.46s/it]\u001b[A\n",
      "Iteration:  21%|██        | 8/38 [00:11<00:43,  1.47s/it]\u001b[A\n",
      "Iteration:  24%|██▎       | 9/38 [00:13<00:42,  1.47s/it]\u001b[A\n",
      "Iteration:  26%|██▋       | 10/38 [00:14<00:41,  1.47s/it]\u001b[A\n",
      "Iteration:  29%|██▉       | 11/38 [00:16<00:39,  1.48s/it]\u001b[A\n",
      "Iteration:  32%|███▏      | 12/38 [00:17<00:38,  1.49s/it]\u001b[A\n",
      "Iteration:  34%|███▍      | 13/38 [00:19<00:37,  1.48s/it]\u001b[A\n",
      "Iteration:  37%|███▋      | 14/38 [00:20<00:35,  1.48s/it]\u001b[A\n",
      "Iteration:  39%|███▉      | 15/38 [00:22<00:34,  1.49s/it]\u001b[A\n",
      "Iteration:  42%|████▏     | 16/38 [00:23<00:32,  1.48s/it]\u001b[A\n",
      "Iteration:  45%|████▍     | 17/38 [00:25<00:31,  1.48s/it]\u001b[A\n",
      "Iteration:  47%|████▋     | 18/38 [00:26<00:29,  1.49s/it]\u001b[A\n",
      "Iteration:  50%|█████     | 19/38 [00:28<00:28,  1.49s/it]\u001b[A\n",
      "Iteration:  53%|█████▎    | 20/38 [00:29<00:26,  1.49s/it]\u001b[A\n",
      "Iteration:  55%|█████▌    | 21/38 [00:31<00:25,  1.50s/it]\u001b[A\n",
      "Iteration:  58%|█████▊    | 22/38 [00:32<00:23,  1.50s/it]\u001b[A\n",
      "Iteration:  61%|██████    | 23/38 [00:34<00:22,  1.50s/it]\u001b[A\n",
      "Iteration:  63%|██████▎   | 24/38 [00:35<00:21,  1.51s/it]\u001b[A\n",
      "Iteration:  66%|██████▌   | 25/38 [00:37<00:19,  1.51s/it]\u001b[A\n",
      "Iteration:  68%|██████▊   | 26/38 [00:38<00:18,  1.51s/it]\u001b[A\n",
      "Iteration:  71%|███████   | 27/38 [00:40<00:16,  1.51s/it]\u001b[A\n",
      "Iteration:  74%|███████▎  | 28/38 [00:41<00:15,  1.51s/it]\u001b[A\n",
      "Iteration:  76%|███████▋  | 29/38 [00:43<00:13,  1.51s/it]\u001b[A\n",
      "Iteration:  79%|███████▉  | 30/38 [00:45<00:12,  1.51s/it]\u001b[A\n",
      "Iteration:  82%|████████▏ | 31/38 [00:46<00:10,  1.51s/it]\u001b[A\n",
      "Iteration:  84%|████████▍ | 32/38 [00:48<00:09,  1.51s/it]\u001b[A\n",
      "Iteration:  87%|████████▋ | 33/38 [00:49<00:07,  1.51s/it]\u001b[A\n",
      "Iteration:  89%|████████▉ | 34/38 [00:51<00:06,  1.51s/it]\u001b[A\n",
      "Iteration:  92%|█████████▏| 35/38 [00:52<00:04,  1.51s/it]\u001b[A\n",
      "Iteration:  95%|█████████▍| 36/38 [00:54<00:03,  1.51s/it]\u001b[A\n",
      "Iteration:  97%|█████████▋| 37/38 [00:55<00:01,  1.52s/it]\u001b[A\n",
      "Iteration: 100%|██████████| 38/38 [00:56<00:00,  1.48s/it]\u001b[A\n",
      "Epoch:  20%|██        | 1/5 [00:56<03:45, 56.31s/it]\n",
      "Iteration:   0%|          | 0/38 [00:00<?, ?it/s]\u001b[A\n",
      "Iteration:   3%|▎         | 1/38 [00:01<00:57,  1.56s/it]\u001b[A\n",
      "Iteration:   5%|▌         | 2/38 [00:03<00:54,  1.52s/it]\u001b[A\n",
      "Iteration:   8%|▊         | 3/38 [00:04<00:53,  1.52s/it]\u001b[A\n",
      "Iteration:  11%|█         | 4/38 [00:06<00:51,  1.52s/it]\u001b[A\n",
      "Iteration:  13%|█▎        | 5/38 [00:07<00:50,  1.53s/it]\u001b[A\n",
      "Iteration:  16%|█▌        | 6/38 [00:09<00:49,  1.53s/it]\u001b[A\n",
      "Iteration:  18%|█▊        | 7/38 [00:10<00:47,  1.54s/it]\u001b[A\n",
      "Iteration:  21%|██        | 8/38 [00:12<00:46,  1.54s/it]\u001b[A\n",
      "Iteration:  24%|██▎       | 9/38 [00:13<00:44,  1.54s/it]\u001b[A\n",
      "Iteration:  26%|██▋       | 10/38 [00:15<00:43,  1.54s/it]\u001b[A\n",
      "Iteration:  29%|██▉       | 11/38 [00:16<00:41,  1.53s/it]\u001b[A\n",
      "Iteration:  32%|███▏      | 12/38 [00:18<00:39,  1.54s/it]\u001b[A\n",
      "Iteration:  34%|███▍      | 13/38 [00:19<00:38,  1.53s/it]\u001b[A\n",
      "Iteration:  37%|███▋      | 14/38 [00:21<00:36,  1.54s/it]\u001b[A\n",
      "Iteration:  39%|███▉      | 15/38 [00:23<00:35,  1.53s/it]\u001b[A\n",
      "Iteration:  42%|████▏     | 16/38 [00:24<00:33,  1.54s/it]\u001b[A\n",
      "Iteration:  45%|████▍     | 17/38 [00:26<00:32,  1.54s/it]\u001b[A\n",
      "Iteration:  47%|████▋     | 18/38 [00:27<00:30,  1.54s/it]\u001b[A\n",
      "Iteration:  50%|█████     | 19/38 [00:29<00:29,  1.53s/it]\u001b[A\n",
      "Iteration:  53%|█████▎    | 20/38 [00:30<00:27,  1.54s/it]\u001b[A\n",
      "Iteration:  55%|█████▌    | 21/38 [00:32<00:26,  1.54s/it]\u001b[A\n",
      "Iteration:  58%|█████▊    | 22/38 [00:33<00:24,  1.54s/it]\u001b[A\n",
      "Iteration:  61%|██████    | 23/38 [00:35<00:23,  1.54s/it]\u001b[A\n",
      "Iteration:  63%|██████▎   | 24/38 [00:36<00:21,  1.54s/it]\u001b[A\n",
      "Iteration:  66%|██████▌   | 25/38 [00:38<00:20,  1.54s/it]\u001b[A\n",
      "Iteration:  68%|██████▊   | 26/38 [00:39<00:18,  1.54s/it]\u001b[A\n",
      "Iteration:  71%|███████   | 27/38 [00:41<00:16,  1.54s/it]\u001b[A\n",
      "Iteration:  74%|███████▎  | 28/38 [00:42<00:15,  1.53s/it]\u001b[A\n",
      "Iteration:  76%|███████▋  | 29/38 [00:44<00:13,  1.54s/it]\u001b[A\n",
      "Iteration:  79%|███████▉  | 30/38 [00:46<00:12,  1.54s/it]\u001b[A\n",
      "Iteration:  82%|████████▏ | 31/38 [00:47<00:10,  1.54s/it]\u001b[A\n",
      "Iteration:  84%|████████▍ | 32/38 [00:49<00:09,  1.54s/it]\u001b[A\n",
      "Iteration:  87%|████████▋ | 33/38 [00:50<00:07,  1.54s/it]\u001b[A\n",
      "Iteration:  89%|████████▉ | 34/38 [00:52<00:06,  1.54s/it]\u001b[A\n",
      "Iteration:  92%|█████████▏| 35/38 [00:53<00:04,  1.54s/it]\u001b[A\n",
      "Iteration:  95%|█████████▍| 36/38 [00:55<00:03,  1.54s/it]\u001b[A\n",
      "Iteration:  97%|█████████▋| 37/38 [00:56<00:01,  1.54s/it]\u001b[A\n",
      "Iteration: 100%|██████████| 38/38 [00:57<00:00,  1.51s/it]\u001b[A\n",
      "Epoch:  40%|████      | 2/5 [01:53<02:50, 56.98s/it]\n",
      "Iteration:   0%|          | 0/38 [00:00<?, ?it/s]\u001b[A\n",
      "Iteration:   3%|▎         | 1/38 [00:01<00:59,  1.62s/it]\u001b[A\n",
      "Iteration:   5%|▌         | 2/38 [00:03<00:56,  1.57s/it]\u001b[A\n",
      "Iteration:   8%|▊         | 3/38 [00:04<00:54,  1.55s/it]\u001b[A\n",
      "Iteration:  11%|█         | 4/38 [00:06<00:52,  1.56s/it]\u001b[A\n",
      "Iteration:  13%|█▎        | 5/38 [00:07<00:51,  1.55s/it]\u001b[A\n",
      "Iteration:  16%|█▌        | 6/38 [00:09<00:49,  1.55s/it]\u001b[A\n",
      "Iteration:  18%|█▊        | 7/38 [00:10<00:48,  1.55s/it]\u001b[A\n",
      "Iteration:  21%|██        | 8/38 [00:12<00:46,  1.56s/it]\u001b[A\n",
      "Iteration:  24%|██▎       | 9/38 [00:13<00:45,  1.55s/it]\u001b[A\n",
      "Iteration:  26%|██▋       | 10/38 [00:15<00:43,  1.55s/it]\u001b[A\n",
      "Iteration:  29%|██▉       | 11/38 [00:17<00:41,  1.55s/it]\u001b[A\n",
      "Iteration:  32%|███▏      | 12/38 [00:18<00:40,  1.55s/it]\u001b[A\n",
      "Iteration:  34%|███▍      | 13/38 [00:20<00:38,  1.56s/it]\u001b[A\n",
      "Iteration:  37%|███▋      | 14/38 [00:21<00:37,  1.56s/it]\u001b[A\n",
      "Iteration:  39%|███▉      | 15/38 [00:23<00:35,  1.56s/it]\u001b[A\n",
      "Iteration:  42%|████▏     | 16/38 [00:24<00:34,  1.56s/it]\u001b[A\n",
      "Iteration:  45%|████▍     | 17/38 [00:26<00:32,  1.56s/it]\u001b[A\n",
      "Iteration:  47%|████▋     | 18/38 [00:28<00:31,  1.57s/it]\u001b[A\n",
      "Iteration:  50%|█████     | 19/38 [00:29<00:29,  1.56s/it]\u001b[A\n",
      "Iteration:  53%|█████▎    | 20/38 [00:31<00:28,  1.57s/it]\u001b[A\n",
      "Iteration:  55%|█████▌    | 21/38 [00:32<00:26,  1.57s/it]\u001b[A\n",
      "Iteration:  58%|█████▊    | 22/38 [00:34<00:25,  1.57s/it]\u001b[A\n",
      "Iteration:  61%|██████    | 23/38 [00:35<00:23,  1.57s/it]\u001b[A\n",
      "Iteration:  63%|██████▎   | 24/38 [00:37<00:21,  1.57s/it]\u001b[A\n",
      "Iteration:  66%|██████▌   | 25/38 [00:39<00:20,  1.56s/it]\u001b[A\n",
      "Iteration:  68%|██████▊   | 26/38 [00:40<00:18,  1.56s/it]\u001b[A\n",
      "Iteration:  71%|███████   | 27/38 [00:42<00:17,  1.56s/it]\u001b[A\n",
      "Iteration:  74%|███████▎  | 28/38 [00:43<00:15,  1.56s/it]\u001b[A\n",
      "Iteration:  76%|███████▋  | 29/38 [00:45<00:14,  1.56s/it]\u001b[A\n",
      "Iteration:  79%|███████▉  | 30/38 [00:46<00:12,  1.56s/it]\u001b[A\n",
      "Iteration:  82%|████████▏ | 31/38 [00:48<00:10,  1.56s/it]\u001b[A\n",
      "Iteration:  84%|████████▍ | 32/38 [00:49<00:09,  1.56s/it]\u001b[A\n",
      "Iteration:  87%|████████▋ | 33/38 [00:51<00:07,  1.56s/it]\u001b[A\n",
      "Iteration:  89%|████████▉ | 34/38 [00:53<00:06,  1.56s/it]\u001b[A\n",
      "Iteration:  92%|█████████▏| 35/38 [00:54<00:04,  1.57s/it]\u001b[A\n",
      "Iteration:  95%|█████████▍| 36/38 [00:56<00:03,  1.57s/it]\u001b[A\n",
      "Iteration:  97%|█████████▋| 37/38 [00:57<00:01,  1.57s/it]\u001b[A\n",
      "Iteration: 100%|██████████| 38/38 [00:58<00:00,  1.54s/it]\u001b[A\n",
      "Epoch:  60%|██████    | 3/5 [02:52<01:55, 57.70s/it]\n",
      "Iteration:   0%|          | 0/38 [00:00<?, ?it/s]\u001b[A\n",
      "Iteration:   3%|▎         | 1/38 [00:01<00:56,  1.52s/it]\u001b[A\n",
      "Iteration:   5%|▌         | 2/38 [00:03<00:54,  1.53s/it]\u001b[A\n",
      "Iteration:   8%|▊         | 3/38 [00:04<00:54,  1.56s/it]\u001b[A\n",
      "Iteration:  11%|█         | 4/38 [00:06<00:53,  1.57s/it]\u001b[A\n",
      "Iteration:  13%|█▎        | 5/38 [00:07<00:51,  1.57s/it]\u001b[A\n",
      "Iteration:  16%|█▌        | 6/38 [00:09<00:49,  1.56s/it]\u001b[A\n",
      "Iteration:  18%|█▊        | 7/38 [00:10<00:48,  1.56s/it]\u001b[A\n",
      "Iteration:  21%|██        | 8/38 [00:12<00:46,  1.56s/it]\u001b[A\n",
      "Iteration:  24%|██▎       | 9/38 [00:14<00:45,  1.57s/it]\u001b[A\n",
      "Iteration:  26%|██▋       | 10/38 [00:15<00:44,  1.58s/it]\u001b[A\n",
      "Iteration:  29%|██▉       | 11/38 [00:17<00:42,  1.57s/it]\u001b[A\n",
      "Iteration:  32%|███▏      | 12/38 [00:18<00:40,  1.57s/it]\u001b[A\n",
      "Iteration:  34%|███▍      | 13/38 [00:20<00:39,  1.58s/it]\u001b[A\n",
      "Iteration:  37%|███▋      | 14/38 [00:22<00:37,  1.58s/it]\u001b[A\n",
      "Iteration:  39%|███▉      | 15/38 [00:23<00:36,  1.58s/it]\u001b[A\n",
      "Iteration:  42%|████▏     | 16/38 [00:25<00:34,  1.58s/it]\u001b[A\n",
      "Iteration:  45%|████▍     | 17/38 [00:26<00:33,  1.58s/it]\u001b[A\n",
      "Iteration:  47%|████▋     | 18/38 [00:28<00:31,  1.58s/it]\u001b[A\n",
      "Iteration:  50%|█████     | 19/38 [00:29<00:30,  1.58s/it]\u001b[A\n",
      "Iteration:  53%|█████▎    | 20/38 [00:31<00:28,  1.58s/it]\u001b[A\n",
      "Iteration:  55%|█████▌    | 21/38 [00:33<00:26,  1.58s/it]\u001b[A\n",
      "Iteration:  58%|█████▊    | 22/38 [00:34<00:25,  1.58s/it]\u001b[A\n",
      "Iteration:  61%|██████    | 23/38 [00:36<00:23,  1.58s/it]\u001b[A\n",
      "Iteration:  63%|██████▎   | 24/38 [00:37<00:22,  1.58s/it]\u001b[A\n",
      "Iteration:  66%|██████▌   | 25/38 [00:39<00:20,  1.58s/it]\u001b[A\n",
      "Iteration:  68%|██████▊   | 26/38 [00:41<00:18,  1.58s/it]\u001b[A\n",
      "Iteration:  71%|███████   | 27/38 [00:42<00:17,  1.58s/it]\u001b[A\n",
      "Iteration:  74%|███████▎  | 28/38 [00:44<00:15,  1.58s/it]\u001b[A\n",
      "Iteration:  76%|███████▋  | 29/38 [00:45<00:14,  1.59s/it]\u001b[A\n",
      "Iteration:  79%|███████▉  | 30/38 [00:47<00:12,  1.59s/it]\u001b[A\n",
      "Iteration:  82%|████████▏ | 31/38 [00:49<00:11,  1.59s/it]\u001b[A\n",
      "Iteration:  84%|████████▍ | 32/38 [00:50<00:09,  1.59s/it]\u001b[A\n",
      "Iteration:  87%|████████▋ | 33/38 [00:52<00:07,  1.59s/it]\u001b[A\n",
      "Iteration:  89%|████████▉ | 34/38 [00:53<00:06,  1.59s/it]\u001b[A\n",
      "Iteration:  92%|█████████▏| 35/38 [00:55<00:04,  1.59s/it]\u001b[A\n",
      "Iteration:  95%|█████████▍| 36/38 [00:57<00:03,  1.59s/it]\u001b[A\n",
      "Iteration:  97%|█████████▋| 37/38 [00:58<00:01,  1.58s/it]\u001b[A\n",
      "Iteration: 100%|██████████| 38/38 [00:59<00:00,  1.56s/it]\u001b[A\n",
      "Epoch:  80%|████████  | 4/5 [03:51<00:58, 58.27s/it]\n",
      "Iteration:   0%|          | 0/38 [00:00<?, ?it/s]\u001b[A\n",
      "Iteration:   3%|▎         | 1/38 [00:01<00:58,  1.57s/it]\u001b[A\n",
      "Iteration:   5%|▌         | 2/38 [00:03<00:56,  1.57s/it]\u001b[A\n",
      "Iteration:   8%|▊         | 3/38 [00:04<00:54,  1.57s/it]\u001b[A\n",
      "Iteration:  11%|█         | 4/38 [00:06<00:53,  1.58s/it]\u001b[A\n",
      "Iteration:  13%|█▎        | 5/38 [00:07<00:52,  1.58s/it]\u001b[A\n",
      "Iteration:  16%|█▌        | 6/38 [00:09<00:50,  1.59s/it]\u001b[A\n",
      "Iteration:  18%|█▊        | 7/38 [00:11<00:49,  1.59s/it]\u001b[A\n",
      "Iteration:  21%|██        | 8/38 [00:12<00:47,  1.59s/it]\u001b[A\n",
      "Iteration:  24%|██▎       | 9/38 [00:14<00:46,  1.59s/it]\u001b[A\n",
      "Iteration:  26%|██▋       | 10/38 [00:15<00:44,  1.60s/it]\u001b[A\n",
      "Iteration:  29%|██▉       | 11/38 [00:17<00:43,  1.59s/it]\u001b[A\n",
      "Iteration:  32%|███▏      | 12/38 [00:19<00:41,  1.59s/it]\u001b[A\n",
      "Iteration:  34%|███▍      | 13/38 [00:20<00:39,  1.59s/it]\u001b[A\n",
      "Iteration:  37%|███▋      | 14/38 [00:22<00:38,  1.59s/it]\u001b[A\n",
      "Iteration:  39%|███▉      | 15/38 [00:23<00:36,  1.60s/it]\u001b[A\n",
      "Iteration:  42%|████▏     | 16/38 [00:25<00:35,  1.60s/it]\u001b[A\n",
      "Iteration:  45%|████▍     | 17/38 [00:27<00:33,  1.60s/it]\u001b[A\n",
      "Iteration:  47%|████▋     | 18/38 [00:28<00:32,  1.60s/it]\u001b[A\n",
      "Iteration:  50%|█████     | 19/38 [00:30<00:30,  1.60s/it]\u001b[A\n",
      "Iteration:  53%|█████▎    | 20/38 [00:31<00:28,  1.60s/it]\u001b[A\n",
      "Iteration:  55%|█████▌    | 21/38 [00:33<00:27,  1.60s/it]\u001b[A\n",
      "Iteration:  58%|█████▊    | 22/38 [00:35<00:25,  1.60s/it]\u001b[A\n",
      "Iteration:  61%|██████    | 23/38 [00:36<00:23,  1.60s/it]\u001b[A\n",
      "Iteration:  63%|██████▎   | 24/38 [00:38<00:22,  1.60s/it]\u001b[A\n",
      "Iteration:  66%|██████▌   | 25/38 [00:39<00:20,  1.60s/it]\u001b[A\n",
      "Iteration:  68%|██████▊   | 26/38 [00:41<00:19,  1.60s/it]\u001b[A\n",
      "Iteration:  71%|███████   | 27/38 [00:43<00:17,  1.60s/it]\u001b[A\n",
      "Iteration:  74%|███████▎  | 28/38 [00:44<00:16,  1.60s/it]\u001b[A\n",
      "Iteration:  76%|███████▋  | 29/38 [00:46<00:14,  1.60s/it]\u001b[A\n",
      "Iteration:  79%|███████▉  | 30/38 [00:48<00:12,  1.60s/it]\u001b[A\n",
      "Iteration:  82%|████████▏ | 31/38 [00:49<00:11,  1.60s/it]\u001b[A\n",
      "Iteration:  84%|████████▍ | 32/38 [00:51<00:09,  1.60s/it]\u001b[A\n",
      "Iteration:  87%|████████▋ | 33/38 [00:52<00:07,  1.60s/it]\u001b[A\n",
      "Iteration:  89%|████████▉ | 34/38 [00:54<00:06,  1.60s/it]\u001b[A\n",
      "Iteration:  92%|█████████▏| 35/38 [00:55<00:04,  1.60s/it]\u001b[A\n",
      "Iteration:  95%|█████████▍| 36/38 [00:57<00:03,  1.59s/it]\u001b[A\n",
      "Iteration:  97%|█████████▋| 37/38 [00:59<00:01,  1.59s/it]\u001b[A\n",
      "Iteration: 100%|██████████| 38/38 [00:59<00:00,  1.57s/it]\u001b[A\n",
      "Epoch: 100%|██████████| 5/5 [04:51<00:00, 58.24s/it]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2023-08-01 09:00:S - Save model to ./finetuned-sentence-embedding\n"
     ]
    }
   ],
   "source": [
    "torch.cuda.empty_cache()\n",
    "modelB.fit(train_objectives=[(train_dataloader, train_loss)],\n",
    "          epochs=num_epochs,\n",
    "           # evaluator=evaluator,\n",
    "            evaluation_steps=5,\n",
    "           output_path='./finetuned-sentence-embedding',\n",
    "          warmup_steps=warmup_steps)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "dc41acd2-7471-4cc1-889b-1a70eb6d21c9",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# modelB.evaluate(evaluator)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4597bff-501a-47e0-83df-a4a672823f18",
   "metadata": {
    "tags": []
   },
   "source": [
    "## 从本地加载finetuned的模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "id": "18fd2552-4321-4c94-8452-2177b731554b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2023-08-01 09:00:S - Load pretrained SentenceTransformer: ./finetuned-sentence-embedding\n",
      "2023-08-01 09:00:S - Use pytorch device: cuda\n"
     ]
    }
   ],
   "source": [
    "modelB = SentenceTransformer('./finetuned-sentence-embedding')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 145,
   "id": "82f99adb-d475-41bc-827b-9fe1dbdd96d8",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# input_sentences_a = ['专属技能碎片可以通过多种途径获得，例如礼包商城-特惠礼包界面可以购买专属技能碎片礼包', \n",
    "#                   '中国首都在北京',\n",
    "#                   '美国首都在华盛顿']\n",
    "# input_sentences_q = ['专属技能碎片在哪里？',\n",
    "#                    '中国首都在哪里？',\n",
    "#                    '美国首都在哪里？']\n",
    "\n",
    "# embeddings = modelB.encode(input_sentences_a+input_sentences_q)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 147,
   "id": "cb77deba-a613-4177-bf04-7f02692614d5",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sentence_transformers import evaluation,util\n",
    "\n",
    "# util.cos_sim(embeddings[:3],embeddings[3:])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 148,
   "id": "807f79e8-002a-4f86-9294-27b11158cbb3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "input_answer  = []\n",
    "input_question  = []\n",
    "for i, (a,b) in enumerate (all_datas):\n",
    "        input_answer.append(a)\n",
    "        input_question.append(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 149,
   "id": "a9bbeb9d-7d2d-4e47-aa4c-3cacb31db498",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 75/75 [00:09<00:00,  8.03it/s]\n",
      "Batches: 100%|██████████| 75/75 [00:02<00:00, 29.04it/s]\n"
     ]
    }
   ],
   "source": [
    "emb_answer = modelB.encode(input_answer)\n",
    "emb_question = modelB.encode(input_question)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 150,
   "id": "90bb0891-fd80-4a90-bdf1-097c43c80e55",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2389, 2389)"
      ]
     },
     "execution_count": 150,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(input_question),len(input_answer)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8715caf-e85a-4690-beb2-0d732a8b244d",
   "metadata": {
    "tags": []
   },
   "source": [
    "## 将question和answer进行cross 对比，生成126*126个结果，再查看这个分布"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 151,
   "id": "e529a082-e4d0-4f0e-85bd-f38160a09cfb",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "cross_simsvalues = util.cos_sim(emb_answer,emb_question).flatten()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 152,
   "id": "23cfc0f1-4468-48bb-8349-1011605d5870",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "cross_sims_s = pd.Series(cross_simsvalues)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 153,
   "id": "cdd17e5a-01cc-481b-9f36-e56944f2cd86",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "N = len(input_question)\n",
    "pos_indices = [ i*N+i for i in range(N)] ##正例的index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 154,
   "id": "92f376bf-da76-4f80-bf93-ca0165f2dbbf",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "count    2389.000000\n",
       "mean        0.698667\n",
       "std         0.105582\n",
       "min         0.275420\n",
       "25%         0.629657\n",
       "50%         0.709966\n",
       "75%         0.779276\n",
       "max         1.000000\n",
       "dtype: float64"
      ]
     },
     "execution_count": 154,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 正样本的得分\n",
    "pos_cross_sims_s = cross_sims_s[pos_indices]\n",
    "pos_cross_sims_s.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 155,
   "id": "a1b58af3-47be-423a-8999-da07609eaa9f",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "count    5.704932e+06\n",
       "mean     6.926032e-02\n",
       "std      1.058858e-01\n",
       "min     -3.266906e-01\n",
       "25%     -1.233283e-03\n",
       "50%      5.932677e-02\n",
       "75%      1.268153e-01\n",
       "max      9.999997e-01\n",
       "dtype: float64"
      ]
     },
     "execution_count": 155,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#负样本得分\n",
    "neg_cross_sims_s = cross_sims_s.drop(pos_indices)\n",
    "neg_cross_sims_s.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 156,
   "id": "98bfbea3-1274-4ea0-91d9-69af1784600c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Axes: ylabel='Count'>"
      ]
     },
     "execution_count": 156,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import seaborn as sns\n",
    "sns.histplot(pos_cross_sims_s, color='green',kde=True)\n",
    " ##负样本较多，只采样一部分进行plot\n",
    "sns.histplot(neg_cross_sims_s.sample(N), color='red',kde=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a9b8002-1cb8-4899-a903-c43fabf37ddc",
   "metadata": {},
   "source": [
    "## 输出具体的结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "id": "7f5224be-74af-410b-b165-e211399bc26b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "def similarity(v1,v2):\n",
    "    dot_product = np.dot(v1, v2)\n",
    "\n",
    "    magnitude_v1 = np.linalg.norm(v1)\n",
    "    magnitude_v2 = np.linalg.norm(v2)\n",
    "\n",
    "    return dot_product / (magnitude_v1 * magnitude_v2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "833ee658-32b0-49ab-b6eb-2c9b258e1762",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "for i in range(len(input_question)):\n",
    "    sims = similarity(emb_answer[i],emb_question[i])\n",
    "    print(f\"Question:{input_question[i]}\\nAnswer:{input_answer[i]}\\n{sims}\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cd63deec-e324-470e-aad4-ff13cabcbaba",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 131,
   "id": "348b3ab6-f42d-4c54-a9b7-3a6223387168",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00, 89.53it/s]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[[{'corpus_id': 117, 'score': 0.36897891759872437},\n",
       "  {'corpus_id': 35, 'score': 0.36897891759872437},\n",
       "  {'corpus_id': 120, 'score': 0.35904332995414734}]]"
      ]
     },
     "execution_count": 131,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "input_queries = ['雷电将军好不好使？']\n",
    "q_embedding = modelB.encode(input_queries)\n",
    "results = util.semantic_search(query_embeddings = q_embedding,corpus_embeddings= emb_answer,top_k=3)\n",
    "results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "37fbf424-9b29-44ba-8300-65aab4b56a35",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.4407898"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "similarity(q_embedding[0],emb_answer[93])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 212,
   "id": "6b7015ab-0ab1-4b5a-bb70-1f1eff19c8cf",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('全力交锋--战斗阶段开始后，跨服到其它战区后，除了攻打首府和两个2个王者遗迹-守卫外（其他遗迹和发射塔为和平状态，不可攻击），还可以攻打该服玩家的城堡，采集田和强化弱化塔。', '战斗阶段是否可以攻击其他战区指挥官？') score:0.4162951409816742\n",
      "('玩家拥有建筑的占领权后，拥有【先锋】权限的玩家，可以开启对决。开启对决后，该玩家在此建筑中的所有部队都将会进入对决状态中，其他势力的拥有【先锋】权限的玩家，可以发起对决；当击败玩家所有进入对决状态的部队后，视为攻击成功。对决连续守住一定的攻击次数，或守住规定的时间，则对决成功，否则对决失败。对决获胜，可获得一定时间的无敌时间，并立即摧毁一定的城防值；对决失败，则击败对决的玩家获得建筑的控制权。', '先锋对决怎么玩，胜负规则是什么？') score:0.33781808614730835\n",
      "('您好，破浪突袭者BW-3的控制技能主要体现在 技能中有一项是潮汐震荡，如果被击目标处在攻击力降低状态，50%概率对其附加[眩晕]（无法普攻和释放主动技能）。从技能定位来看，其更偏向攻击，但防守效果也不错。', '小蓝是拥有控制技能的重装机兵，这个控制技能怎么理解？它更适合攻击还是防守？') score:0.29779693484306335\n"
     ]
    }
   ],
   "source": [
    "for ret in results[0]:\n",
    "    print(f\"{all_datas[ret['corpus_id']]} score:{ret['score']}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ec80db02-8714-4132-8457-2acf024b1a59",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "2d47bd28-2482-47cb-b058-9f2f8bce9944",
   "metadata": {},
   "source": [
    "# 使用pre trained 模型对比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 157,
   "id": "1b06da68-f9ef-46a6-8665-a2369c9a012b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2023-08-01 09:01:S - Load pretrained SentenceTransformer: sentence-transformers/paraphrase-multilingual-mpnet-base-v2\n",
      "2023-08-01 09:01:S - Use pytorch device: cuda\n"
     ]
    }
   ],
   "source": [
    "modelA = SentenceTransformer('sentence-transformers/paraphrase-multilingual-mpnet-base-v2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 158,
   "id": "51f4ecb2-24f9-4847-846d-87aba754e7cd",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 75/75 [00:09<00:00,  8.16it/s]\n",
      "Batches: 100%|██████████| 75/75 [00:02<00:00, 29.57it/s]\n"
     ]
    }
   ],
   "source": [
    "emb_answer = modelA.encode(input_answer)\n",
    "emb_question = modelA.encode(input_question)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 159,
   "id": "8af4b624-1c51-469a-8f6c-61fe7176aca9",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "cross_simsvalues = util.cos_sim(emb_answer,emb_question).flatten()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "id": "78129947-eb0a-4950-a5e4-19c41375f2f0",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "cross_sims_s = pd.Series(cross_simsvalues)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "id": "d2814786-c424-43a0-81ef-184b6a0e432c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "count    2389.000000\n",
       "mean        0.593277\n",
       "std         0.168812\n",
       "min        -0.010802\n",
       "25%         0.499096\n",
       "50%         0.615271\n",
       "75%         0.716594\n",
       "max         1.000000\n",
       "dtype: float64"
      ]
     },
     "execution_count": 161,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 正样本的得分\n",
    "pos_cross_sims_s = cross_sims_s[pos_indices]\n",
    "pos_cross_sims_s.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "id": "070a4f24-27a9-41db-b541-386a4998f3a1",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "count    5.704932e+06\n",
       "mean     2.514530e-01\n",
       "std      1.344531e-01\n",
       "min     -1.834030e-01\n",
       "25%      1.541162e-01\n",
       "50%      2.432678e-01\n",
       "75%      3.402092e-01\n",
       "max      1.000000e+00\n",
       "dtype: float64"
      ]
     },
     "execution_count": 162,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#负样本得分\n",
    "neg_cross_sims_s = cross_sims_s.drop(pos_indices)\n",
    "neg_cross_sims_s.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "id": "24c8a709-d438-42c9-937b-5cb7e89d3137",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Axes: ylabel='Count'>"
      ]
     },
     "execution_count": 163,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import seaborn as sns\n",
    "sns.histplot(pos_cross_sims_s, color='green',kde=True)\n",
    " ##负样本较多，只采样一部分进行plot\n",
    "sns.histplot(neg_cross_sims_s.sample(N), color='red',kde=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7cc99a0-ee6a-4902-b8af-b7c6cc9da18a",
   "metadata": {},
   "source": [
    "# 部署模型到sagemaker"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "57dc4832-b17a-47b0-8662-4ced85f29952",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
      "To disable this warning, you can either:\n",
      "\t- Avoid using `tokenizers` before the fork if possible\n",
      "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n",
      "Requirement already satisfied: sagemaker in /opt/conda/lib/python3.10/site-packages (2.154.0)\n",
      "Collecting sagemaker\n",
      "  Downloading sagemaker-2.169.0.tar.gz (851 kB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m851.8/851.8 kB\u001b[0m \u001b[31m8.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m\n",
      "\u001b[?25h  Preparing metadata (setup.py) ... \u001b[?25ldone\n",
      "\u001b[?25hCollecting attrs<24,>=23.1.0 (from sagemaker)\n",
      "  Using cached attrs-23.1.0-py3-none-any.whl (61 kB)\n",
      "Requirement already satisfied: boto3<2.0,>=1.26.131 in /opt/conda/lib/python3.10/site-packages (from sagemaker) (1.26.132)\n",
      "Requirement already satisfied: cloudpickle==2.2.1 in /opt/conda/lib/python3.10/site-packages (from sagemaker) (2.2.1)\n",
      "Requirement already satisfied: google-pasta in /opt/conda/lib/python3.10/site-packages (from sagemaker) (0.2.0)\n",
      "Requirement already satisfied: numpy<2.0,>=1.9.0 in /opt/conda/lib/python3.10/site-packages (from sagemaker) (1.23.5)\n",
      "Requirement already satisfied: protobuf<4.0,>=3.1 in /opt/conda/lib/python3.10/site-packages (from sagemaker) (3.20.3)\n",
      "Requirement already satisfied: protobuf3-to-dict<1.0,>=0.1.5 in /opt/conda/lib/python3.10/site-packages (from sagemaker) (0.1.5)\n",
      "Requirement already satisfied: smdebug_rulesconfig==1.0.1 in /opt/conda/lib/python3.10/site-packages (from sagemaker) (1.0.1)\n",
      "Requirement already satisfied: importlib-metadata<5.0,>=1.4.0 in /opt/conda/lib/python3.10/site-packages (from sagemaker) (4.13.0)\n",
      "Requirement already satisfied: packaging>=20.0 in /opt/conda/lib/python3.10/site-packages (from sagemaker) (23.1)\n",
      "Requirement already satisfied: pandas in /opt/conda/lib/python3.10/site-packages (from sagemaker) (2.0.1)\n",
      "Requirement already satisfied: pathos in /opt/conda/lib/python3.10/site-packages (from sagemaker) (0.3.0)\n",
      "Requirement already satisfied: schema in /opt/conda/lib/python3.10/site-packages (from sagemaker) (0.7.5)\n",
      "Collecting PyYAML==6.0 (from sagemaker)\n",
      "  Using cached PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (682 kB)\n",
      "Requirement already satisfied: jsonschema in /opt/conda/lib/python3.10/site-packages (from sagemaker) (4.17.3)\n",
      "Requirement already satisfied: platformdirs in /opt/conda/lib/python3.10/site-packages (from sagemaker) (3.5.0)\n",
      "Requirement already satisfied: tblib==1.7.0 in /opt/conda/lib/python3.10/site-packages (from sagemaker) (1.7.0)\n",
      "Requirement already satisfied: botocore<1.30.0,>=1.29.132 in /opt/conda/lib/python3.10/site-packages (from boto3<2.0,>=1.26.131->sagemaker) (1.29.132)\n",
      "Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /opt/conda/lib/python3.10/site-packages (from boto3<2.0,>=1.26.131->sagemaker) (1.0.1)\n",
      "Requirement already satisfied: s3transfer<0.7.0,>=0.6.0 in /opt/conda/lib/python3.10/site-packages (from boto3<2.0,>=1.26.131->sagemaker) (0.6.1)\n",
      "Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.10/site-packages (from importlib-metadata<5.0,>=1.4.0->sagemaker) (3.15.0)\n",
      "Requirement already satisfied: six in /opt/conda/lib/python3.10/site-packages (from protobuf3-to-dict<1.0,>=0.1.5->sagemaker) (1.16.0)\n",
      "Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /opt/conda/lib/python3.10/site-packages (from jsonschema->sagemaker) (0.19.3)\n",
      "Requirement already satisfied: python-dateutil>=2.8.2 in /opt/conda/lib/python3.10/site-packages (from pandas->sagemaker) (2.8.2)\n",
      "Requirement already satisfied: pytz>=2020.1 in /opt/conda/lib/python3.10/site-packages (from pandas->sagemaker) (2023.3)\n",
      "Requirement already satisfied: tzdata>=2022.1 in /opt/conda/lib/python3.10/site-packages (from pandas->sagemaker) (2023.3)\n",
      "Requirement already satisfied: ppft>=1.7.6.6 in /opt/conda/lib/python3.10/site-packages (from pathos->sagemaker) (1.7.6.6)\n",
      "Requirement already satisfied: dill>=0.3.6 in /opt/conda/lib/python3.10/site-packages (from pathos->sagemaker) (0.3.6)\n",
      "Requirement already satisfied: pox>=0.3.2 in /opt/conda/lib/python3.10/site-packages (from pathos->sagemaker) (0.3.2)\n",
      "Requirement already satisfied: multiprocess>=0.70.14 in /opt/conda/lib/python3.10/site-packages (from pathos->sagemaker) (0.70.14)\n",
      "Requirement already satisfied: contextlib2>=0.5.5 in /opt/conda/lib/python3.10/site-packages (from schema->sagemaker) (21.6.0)\n",
      "Requirement already satisfied: urllib3<1.27,>=1.25.4 in /opt/conda/lib/python3.10/site-packages (from botocore<1.30.0,>=1.29.132->boto3<2.0,>=1.26.131->sagemaker) (1.26.15)\n",
      "Building wheels for collected packages: sagemaker\n",
      "  Building wheel for sagemaker (setup.py) ... \u001b[?25ldone\n",
      "\u001b[?25h  Created wheel for sagemaker: filename=sagemaker-2.169.0-py2.py3-none-any.whl size=1158252 sha256=0ec721d00f4427b64ea6d9d4e052bb5989328fde366bb4acd16933fb90d67f82\n",
      "  Stored in directory: /root/.cache/pip/wheels/42/17/69/c2089332a0db669b4a27888e1d76e825168014112d5eb44231\n",
      "Successfully built sagemaker\n",
      "Installing collected packages: PyYAML, attrs, sagemaker\n",
      "  Attempting uninstall: PyYAML\n",
      "    Found existing installation: PyYAML 5.4.1\n",
      "    Uninstalling PyYAML-5.4.1:\n",
      "      Successfully uninstalled PyYAML-5.4.1\n",
      "  Attempting uninstall: attrs\n",
      "    Found existing installation: attrs 22.2.0\n",
      "    Uninstalling attrs-22.2.0:\n",
      "      Successfully uninstalled attrs-22.2.0\n",
      "  Attempting uninstall: sagemaker\n",
      "    Found existing installation: sagemaker 2.154.0\n",
      "    Uninstalling sagemaker-2.154.0:\n",
      "      Successfully uninstalled sagemaker-2.154.0\n",
      "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
      "awscli 1.27.132 requires PyYAML<5.5,>=3.10, but you have pyyaml 6.0 which is incompatible.\u001b[0m\u001b[31m\n",
      "\u001b[0mSuccessfully installed PyYAML-6.0 attrs-23.1.0 sagemaker-2.169.0\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m"
     ]
    }
   ],
   "source": [
    "!pip install -U sagemaker"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0490240-edff-4fff-8eec-bd295bf43f99",
   "metadata": {},
   "source": [
    "## 2. 把模型拷贝到S3为后续部署做准备"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "df4a6f16-63af-4c84-9dda-0af0dfa7b487",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import sagemaker\n",
    "from sagemaker import image_uris\n",
    "import boto3\n",
    "import os\n",
    "import time\n",
    "import json\n",
    "\n",
    "role = sagemaker.get_execution_role()  # execution role for the endpoint\n",
    "sess = sagemaker.session.Session()  # sagemaker session for interacting with different AWS APIs\n",
    "bucket = sess.default_bucket()  # bucket to house artifacts\n",
    "\n",
    "region = sess._region_name\n",
    "account_id = sess.account_id()\n",
    "\n",
    "s3_client = boto3.client(\"s3\")\n",
    "sm_client = boto3.client(\"sagemaker\")\n",
    "smr_client = boto3.client(\"sagemaker-runtime\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "2fb24429-b2e5-4259-bd2d-70aa006c8cd1",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "s3_code_prefix: LLM-RAG/workshop/finetuned-sentence2emb_deploy_code\n",
      "model_snapshot_path: ./finetuned-sentence-embedding\n"
     ]
    }
   ],
   "source": [
    "s3_model_prefix = \"LLM-RAG/workshop/finetuned-sentence2emb-model\"  # folder where model checkpoint will go\n",
    "model_snapshot_path = \"./finetuned-sentence-embedding\"\n",
    "s3_code_prefix = \"LLM-RAG/workshop/finetuned-sentence2emb_deploy_code\"\n",
    "print(f\"s3_code_prefix: {s3_code_prefix}\")\n",
    "print(f\"model_snapshot_path: {model_snapshot_path}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "e53e83fd-305a-42f8-83cf-e0a17779eaac",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
      "To disable this warning, you can either:\n",
      "\t- Avoid using `tokenizers` before the fork if possible\n",
      "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n",
      "upload: finetuned-sentence-embedding/config_sentence_transformers.json to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/config_sentence_transformers.json\n",
      "upload: finetuned-sentence-embedding/config.json to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/config.json\n",
      "upload: finetuned-sentence-embedding/1_Pooling/config.json to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/1_Pooling/config.json\n",
      "upload: finetuned-sentence-embedding/modules.json to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/modules.json\n",
      "upload: finetuned-sentence-embedding/README.md to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/README.md\n",
      "upload: finetuned-sentence-embedding/eval/.ipynb_checkpoints/similarity_evaluation_results-checkpoint.csv to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/eval/.ipynb_checkpoints/similarity_evaluation_results-checkpoint.csv\n",
      "upload: finetuned-sentence-embedding/special_tokens_map.json to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/special_tokens_map.json\n",
      "upload: finetuned-sentence-embedding/eval/similarity_evaluation_results.csv to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/eval/similarity_evaluation_results.csv\n",
      "upload: finetuned-sentence-embedding/sentence_bert_config.json to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/sentence_bert_config.json\n",
      "upload: finetuned-sentence-embedding/tokenizer_config.json to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/tokenizer_config.json\n",
      "upload: finetuned-sentence-embedding/tokenizer.json to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/tokenizer.json\n",
      "upload: finetuned-sentence-embedding/sentencepiece.bpe.model to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/sentencepiece.bpe.model\n",
      "upload: finetuned-sentence-embedding/pytorch_model.bin to s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/pytorch_model.bin\n"
     ]
    }
   ],
   "source": [
    "!aws s3 cp --recursive {model_snapshot_path} s3://{bucket}/{s3_model_prefix}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e4c4651-d731-4e8d-8deb-350918d8d721",
   "metadata": {},
   "source": [
    "### 3. 模型部署准备（entrypoint脚本，容器镜像，服务配置）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "id": "8a07ff35-d547-4df3-b511-4be2862dcb6e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Image going to be used is ---- > 763104351884.dkr.ecr.us-east-2.amazonaws.com/djl-inference:0.21.0-deepspeed0.8.3-cu117\n"
     ]
    }
   ],
   "source": [
    "inference_image_uri = (\n",
    "    f\"763104351884.dkr.ecr.{region}.amazonaws.com/djl-inference:0.21.0-deepspeed0.8.3-cu117\"\n",
    ")\n",
    "\n",
    "#中国区需要替换为下面的image_uri\n",
    "# inference_image_uri = (\n",
    "#     f\"727897471807.dkr.ecr.{region}.amazonaws.com.cn/djl-inference:0.21.0-deepspeed0.8.3-cu117\"\n",
    "# )\n",
    "\n",
    "print(f\"Image going to be used is ---- > {inference_image_uri}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "id": "4858bfe1-0392-41fd-8c46-d4a04a520397",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
      "To disable this warning, you can either:\n",
      "\t- Avoid using `tokenizers` before the fork if possible\n",
      "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n"
     ]
    }
   ],
   "source": [
    "!mkdir -p sentence2emb_deploy_code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "5fe26158-4b50-4659-a869-6d64f3d152e4",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting sentence2emb_deploy_code/model.py\n"
     ]
    }
   ],
   "source": [
    "%%writefile sentence2emb_deploy_code/model.py\n",
    "from djl_python import Input, Output\n",
    "import torch\n",
    "import logging\n",
    "import math\n",
    "import os\n",
    "from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer, AutoModel\n",
    "\n",
    "device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n",
    "print(f'--device={device}')\n",
    "\n",
    "\n",
    "def load_model(properties):\n",
    "    tensor_parallel = properties[\"tensor_parallel_degree\"]\n",
    "    model_location = properties['model_dir']\n",
    "    if \"model_id\" in properties:\n",
    "        model_location = properties['model_id']\n",
    "    logging.info(f\"Loading model in {model_location}\")\n",
    "    \n",
    "    tokenizer = AutoTokenizer.from_pretrained(model_location)\n",
    "   \n",
    "    model = AutoModel.from_pretrained(\n",
    "        model_location, \n",
    "        # device_map=\"balanced_low_0\", \n",
    "        #load_in_8bit=True\n",
    "    )\n",
    "    # load the model on GPU\n",
    "    model.to(device) \n",
    "    model.requires_grad_(False)\n",
    "    model.eval()\n",
    "    \n",
    "    return model, tokenizer\n",
    "\n",
    "\n",
    "model = None\n",
    "tokenizer = None\n",
    "generator = None\n",
    "\n",
    "def mean_pooling(model_output, attention_mask):\n",
    "    token_embeddings = model_output[0].to(device) #First element of model_output contains all token embeddings\n",
    "    input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float().to(device)\n",
    "    return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)\n",
    "\n",
    "\n",
    "def handle(inputs: Input):\n",
    "    global model, tokenizer\n",
    "    if not model:\n",
    "        model, tokenizer = load_model(inputs.get_properties())\n",
    "\n",
    "    if inputs.is_empty():\n",
    "        return None\n",
    "    data = inputs.get_as_json()\n",
    "    \n",
    "    input_sentences = data[\"inputs\"]\n",
    "    params = data[\"parameters\"]\n",
    "    logging.info(f\"inputs: {input_sentences}\")\n",
    "    logging.info(f\"parameters: {params}\")\n",
    "    \n",
    "    encoded_input = tokenizer(input_sentences, padding=True, truncation=True, return_tensors='pt').to(device)\n",
    "    # Compute token embeddings\n",
    "    with torch.no_grad():\n",
    "        model_output = model(**encoded_input)\n",
    "\n",
    "    # Perform pooling. In this case, max pooling.\n",
    "    sentence_embeddings = mean_pooling(model_output, encoded_input['attention_mask']).to(device).cpu().numpy()\n",
    "\n",
    "#     # preprocess\n",
    "#     input_ids = tokenizer(input_sentences, return_tensors=\"pt\").input_ids\n",
    "#     # pass inputs with all kwargs in data\n",
    "#     if params is not None:\n",
    "#         outputs = model.generate(input_ids, **params)\n",
    "#     else:\n",
    "#         outputs = model.generate(input_ids)\n",
    "\n",
    "#     # postprocess the prediction\n",
    "#     prediction = tokenizer.decode(outputs[0], skip_special_tokens=True)\n",
    "    \n",
    "    result = {\"sentence_embeddings\": sentence_embeddings}\n",
    "    return Output().add_as_json(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5c02fa9-d046-42a7-88fc-fc81fe890313",
   "metadata": {},
   "source": [
    "#### Note: option.s3url 需要按照自己的账号进行修改"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "64254ec0-69ab-4c2f-a9bb-05f259ab5218",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting sentence2emb_deploy_code/serving.properties\n"
     ]
    }
   ],
   "source": [
    "%%writefile sentence2emb_deploy_code/serving.properties\n",
    "engine=Python\n",
    "option.tensor_parallel_degree=1\n",
    "option.s3url = s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "d76dad38-02f0-46f9-9121-9cb5155d7a76",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
      "To disable this warning, you can either:\n",
      "\t- Avoid using `tokenizers` before the fork if possible\n",
      "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n",
      "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
      "To disable this warning, you can either:\n",
      "\t- Avoid using `tokenizers` before the fork if possible\n",
      "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n",
      "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
      "To disable this warning, you can either:\n",
      "\t- Avoid using `tokenizers` before the fork if possible\n",
      "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n",
      "sentence2emb_deploy_code/\n",
      "sentence2emb_deploy_code/model.py\n",
      "sentence2emb_deploy_code/serving.properties\n"
     ]
    }
   ],
   "source": [
    "!rm s2e_model.tar.gz\n",
    "!cd sentence2emb_deploy_code && rm -rf \".ipynb_checkpoints\"\n",
    "!tar czvf s2e_model.tar.gz sentence2emb_deploy_code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "id": "76d3d300-4d4d-4ea3-a7d8-2667619cd727",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "S3 Code or Model tar ball uploaded to --- > s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb_deploy_code/s2e_model.tar.gz\n"
     ]
    }
   ],
   "source": [
    "s3_code_artifact = sess.upload_data(\"s2e_model.tar.gz\", bucket, s3_code_prefix)\n",
    "print(f\"S3 Code or Model tar ball uploaded to --- > {s3_code_artifact}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc1a07e1-0955-497f-ba2d-9991a6deb833",
   "metadata": {},
   "source": [
    "### 4. 创建模型 & 创建endpoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "id": "b9318f47-36c1-4f16-962b-bdfe84c77c16",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "finetuned-paraphrase-2023-07-05-03-14-23-508\n",
      "Image going to be used is ---- > 763104351884.dkr.ecr.us-east-2.amazonaws.com/djl-inference:0.21.0-deepspeed0.8.3-cu117\n",
      "Created Model: arn:aws:sagemaker:us-east-2:946277762357:model/finetuned-paraphrase-2023-07-05-03-14-23-508\n"
     ]
    }
   ],
   "source": [
    "from sagemaker.utils import name_from_base\n",
    "import boto3\n",
    "\n",
    "model_name = name_from_base(\"finetuned-paraphrase\") #Note: Need to specify model_name\n",
    "print(model_name)\n",
    "print(f\"Image going to be used is ---- > {inference_image_uri}\")\n",
    "\n",
    "create_model_response = sm_client.create_model(\n",
    "    ModelName=model_name,\n",
    "    ExecutionRoleArn=role,\n",
    "    PrimaryContainer={\n",
    "        \"Image\": inference_image_uri,\n",
    "        \"ModelDataUrl\": s3_code_artifact\n",
    "    },\n",
    "    \n",
    ")\n",
    "model_arn = create_model_response[\"ModelArn\"]\n",
    "\n",
    "print(f\"Created Model: {model_arn}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9a7a2371-de79-4240-b029-80c15a674a7f",
   "metadata": {},
   "source": [
    "###  如果批量创建索引量较多，建议改成\"InstanceType\": \"ml.g4dn.xlarge\","
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "id": "e337d531-3324-4ae4-ac76-66c3418fd548",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'EndpointConfigArn': 'arn:aws:sagemaker:us-east-2:946277762357:endpoint-config/finetuned-paraphrase-2023-07-05-03-14-23-508-config',\n",
       " 'ResponseMetadata': {'RequestId': '0b754ef3-6cb2-4243-bd14-518fbf35d080',\n",
       "  'HTTPStatusCode': 200,\n",
       "  'HTTPHeaders': {'x-amzn-requestid': '0b754ef3-6cb2-4243-bd14-518fbf35d080',\n",
       "   'content-type': 'application/x-amz-json-1.1',\n",
       "   'content-length': '132',\n",
       "   'date': 'Wed, 05 Jul 2023 03:14:30 GMT'},\n",
       "  'RetryAttempts': 0}}"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "endpoint_config_name = f\"{model_name}-config\"\n",
    "endpoint_name = f\"{model_name}-endpoint\"\n",
    "\n",
    "endpoint_config_response = sm_client.create_endpoint_config(\n",
    "    EndpointConfigName=endpoint_config_name,\n",
    "    ProductionVariants=[\n",
    "        {\n",
    "            \"VariantName\": \"variant1\",\n",
    "            \"ModelName\": model_name,\n",
    "            \"InstanceType\": \"ml.m5.2xlarge\",\n",
    "            \"InitialInstanceCount\": 1,\n",
    "            # \"VolumeSizeInGB\" : 400,\n",
    "            # \"ModelDataDownloadTimeoutInSeconds\": 2400,\n",
    "            \"ContainerStartupHealthCheckTimeoutInSeconds\": 10*60,\n",
    "        },\n",
    "    ],\n",
    ")\n",
    "endpoint_config_response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "id": "75f6a4b6-c36a-4ec5-8dd9-35b237ba55ba",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #800000; text-decoration-color: #800000\">╭─────────────────────────────── </span><span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Traceback </span><span style=\"color: #bf7f7f; text-decoration-color: #bf7f7f; font-weight: bold\">(most recent call last)</span><span style=\"color: #800000; text-decoration-color: #800000\"> ────────────────────────────────╮</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/tmp/ipykernel_1225/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">4188345917.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">1</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">&lt;module&gt;</span>                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000; font-style: italic\">[Errno 2] No such file or directory: '/tmp/ipykernel_1225/4188345917.py'</span>                         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/opt/conda/lib/python3.10/site-packages/botocore/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">client.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">530</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">_api_call</span>                      <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 527 │   │   │   │   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">f\"{</span>py_operation_name<span style=\"color: #808000; text-decoration-color: #808000\">}() only accepts keyword arguments.\"</span>              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 528 │   │   │   │   </span>)                                                                         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 529 │   │   │   # The \"self\" in this scope is referring to the BaseClient.</span>                    <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span> 530 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._make_api_call(operation_name, kwargs)                            <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 531 │   │   </span>                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 532 │   │   </span>_api_call.<span style=\"color: #ff0000; text-decoration-color: #ff0000\">__name__</span> = <span style=\"color: #00ffff; text-decoration-color: #00ffff\">str</span>(py_operation_name)                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 533 </span>                                                                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/opt/conda/lib/python3.10/site-packages/botocore/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">client.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">960</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">_make_api_call</span>                 <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 957 │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">if</span> http.status_code &gt;= <span style=\"color: #0000ff; text-decoration-color: #0000ff\">300</span>:                                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 958 │   │   │   </span>error_code = parsed_response.get(<span style=\"color: #808000; text-decoration-color: #808000\">\"Error\"</span>, {}).get(<span style=\"color: #808000; text-decoration-color: #808000\">\"Code\"</span>)                     <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 959 │   │   │   </span>error_class = <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.exceptions.from_code(error_code)                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span> 960 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">raise</span> error_class(parsed_response, operation_name)                            <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 961 │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">else</span>:                                                                             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 962 │   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> parsed_response                                                        <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 963 </span>                                                                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n",
       "<span style=\"color: #800000; text-decoration-color: #800000\">╰──────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
       "<span style=\"color: #ff0000; text-decoration-color: #ff0000; font-weight: bold\">ClientError: </span>An error occurred <span style=\"font-weight: bold\">(</span>ValidationException<span style=\"font-weight: bold\">)</span> when calling the CreateEndpoint operation: Cannot create \n",
       "already existing endpoint \n",
       "<span style=\"color: #008000; text-decoration-color: #008000\">\"arn:aws:sagemaker:us-east-2:946277762357:endpoint/finetuned-paraphrase-2023-07-05-03-14-23-508-endpoint\"</span>.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[31m╭─\u001b[0m\u001b[31m──────────────────────────────\u001b[0m\u001b[31m \u001b[0m\u001b[1;31mTraceback \u001b[0m\u001b[1;2;31m(most recent call last)\u001b[0m\u001b[31m \u001b[0m\u001b[31m───────────────────────────────\u001b[0m\u001b[31m─╮\u001b[0m\n",
       "\u001b[31m│\u001b[0m \u001b[2;33m/tmp/ipykernel_1225/\u001b[0m\u001b[1;33m4188345917.py\u001b[0m:\u001b[94m1\u001b[0m in \u001b[92m<module>\u001b[0m                                                  \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m \u001b[3;31m[Errno 2] No such file or directory: '/tmp/ipykernel_1225/4188345917.py'\u001b[0m                         \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m \u001b[2;33m/opt/conda/lib/python3.10/site-packages/botocore/\u001b[0m\u001b[1;33mclient.py\u001b[0m:\u001b[94m530\u001b[0m in \u001b[92m_api_call\u001b[0m                      \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 527 \u001b[0m\u001b[2m│   │   │   │   │   \u001b[0m\u001b[33mf\u001b[0m\u001b[33m\"\u001b[0m\u001b[33m{\u001b[0mpy_operation_name\u001b[33m}\u001b[0m\u001b[33m() only accepts keyword arguments.\u001b[0m\u001b[33m\"\u001b[0m              \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 528 \u001b[0m\u001b[2m│   │   │   │   \u001b[0m)                                                                         \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 529 \u001b[0m\u001b[2m│   │   │   \u001b[0m\u001b[2m# The \"self\" in this scope is referring to the BaseClient.\u001b[0m                    \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m 530 \u001b[2m│   │   │   \u001b[0m\u001b[94mreturn\u001b[0m \u001b[96mself\u001b[0m._make_api_call(operation_name, kwargs)                            \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 531 \u001b[0m\u001b[2m│   │   \u001b[0m                                                                                  \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 532 \u001b[0m\u001b[2m│   │   \u001b[0m_api_call.\u001b[91m__name__\u001b[0m = \u001b[96mstr\u001b[0m(py_operation_name)                                       \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 533 \u001b[0m                                                                                          \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m \u001b[2;33m/opt/conda/lib/python3.10/site-packages/botocore/\u001b[0m\u001b[1;33mclient.py\u001b[0m:\u001b[94m960\u001b[0m in \u001b[92m_make_api_call\u001b[0m                 \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 957 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mif\u001b[0m http.status_code >= \u001b[94m300\u001b[0m:                                                       \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 958 \u001b[0m\u001b[2m│   │   │   \u001b[0merror_code = parsed_response.get(\u001b[33m\"\u001b[0m\u001b[33mError\u001b[0m\u001b[33m\"\u001b[0m, {}).get(\u001b[33m\"\u001b[0m\u001b[33mCode\u001b[0m\u001b[33m\"\u001b[0m)                     \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 959 \u001b[0m\u001b[2m│   │   │   \u001b[0merror_class = \u001b[96mself\u001b[0m.exceptions.from_code(error_code)                           \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m 960 \u001b[2m│   │   │   \u001b[0m\u001b[94mraise\u001b[0m error_class(parsed_response, operation_name)                            \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 961 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94melse\u001b[0m:                                                                             \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 962 \u001b[0m\u001b[2m│   │   │   \u001b[0m\u001b[94mreturn\u001b[0m parsed_response                                                        \u001b[31m│\u001b[0m\n",
       "\u001b[31m│\u001b[0m   \u001b[2m 963 \u001b[0m                                                                                          \u001b[31m│\u001b[0m\n",
       "\u001b[31m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n",
       "\u001b[1;91mClientError: \u001b[0mAn error occurred \u001b[1m(\u001b[0mValidationException\u001b[1m)\u001b[0m when calling the CreateEndpoint operation: Cannot create \n",
       "already existing endpoint \n",
       "\u001b[32m\"arn:aws:sagemaker:us-east-2:946277762357:endpoint/finetuned-paraphrase-2023-07-05-03-14-23-508-endpoint\"\u001b[0m.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "create_endpoint_response = sm_client.create_endpoint(\n",
    "    EndpointName=f\"{endpoint_name}\", EndpointConfigName=endpoint_config_name\n",
    ")\n",
    "print(f\"Created Endpoint: {create_endpoint_response['EndpointArn']}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "277cc50a-d67e-4d01-ae58-18af86bf6259",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Status: InService\n",
      "Arn: arn:aws:sagemaker:us-east-2:946277762357:endpoint/finetuned-paraphrase-2023-07-04-16-08-10-303-endpoint\n",
      "Status: InService\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "\n",
    "resp = sm_client.describe_endpoint(EndpointName=endpoint_name)\n",
    "status = resp[\"EndpointStatus\"]\n",
    "print(\"Status: \" + status)\n",
    "\n",
    "while status == \"Creating\":\n",
    "    time.sleep(60)\n",
    "    resp = sm_client.describe_endpoint(EndpointName=endpoint_name)\n",
    "    status = resp[\"EndpointStatus\"]\n",
    "    print(\"Status: \" + status)\n",
    "\n",
    "print(\"Arn: \" + resp[\"EndpointArn\"])\n",
    "print(\"Status: \" + status)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef9ac01c-e8d9-4887-be4e-baded6d36abc",
   "metadata": {},
   "source": [
    "## 5. 模型测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "1bef7a45-2484-4c77-8b14-1f6d5fea6b01",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def get_vector_by_sm_endpoint(questions, sm_client, endpoint_name):\n",
    "    parameters = {\n",
    "        \"max_new_tokens\": 50,\n",
    "        \"temperature\": 0,\n",
    "        \"min_length\": 10,\n",
    "        \"no_repeat_ngram_size\": 2,\n",
    "    }\n",
    "\n",
    "    response_model = sm_client.invoke_endpoint(\n",
    "        EndpointName=endpoint_name,\n",
    "        Body=json.dumps(\n",
    "            {\n",
    "                \"inputs\": questions,\n",
    "                \"parameters\": parameters\n",
    "            }\n",
    "        ),\n",
    "        ContentType=\"application/json\",\n",
    "    )\n",
    "    json_str = response_model['Body'].read().decode('utf8')\n",
    "    json_obj = json.loads(json_str)\n",
    "    embeddings = json_obj['sentence_embeddings']\n",
    "    return embeddings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "61b0cb25-1e16-4a70-a77c-f5e644d1166e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "prompts1 = \"\"\"专属技能碎片在哪里获得？\"\"\"\n",
    "prompts1 = \"\"\"中国首都在哪里？\"\"\"\n",
    "\n",
    "emb1 = get_vector_by_sm_endpoint(prompts1, smr_client, endpoint_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "2f37256a-7fa3-4e4c-b0c5-f17e0e8f858a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "prompts2 = \"\"\"专属技能碎片可以通过多种途径获得，例如礼包商城-特惠礼包界面可以购买专属技能碎片礼包\"\"\"\n",
    "emb2 = get_vector_by_sm_endpoint(prompts2, smr_client, endpoint_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "9377d20d-31c8-493e-9247-135052e35cbb",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[-0.0653]])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "util.cos_sim(emb1,emb2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f3a2f25-e206-439e-b8ee-b5f4216f09a9",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "availableInstances": [
   {
    "_defaultOrder": 0,
    "_isFastLaunch": true,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 4,
    "name": "ml.t3.medium",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 1,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.t3.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 2,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.t3.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 3,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.t3.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 4,
    "_isFastLaunch": true,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.m5.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 5,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.m5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 6,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.m5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 7,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.m5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 8,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.m5.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 9,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.m5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 10,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.m5.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 11,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.m5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 12,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.m5d.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 13,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.m5d.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 14,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.m5d.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 15,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.m5d.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 16,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.m5d.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 17,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.m5d.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 18,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.m5d.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 19,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.m5d.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 20,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": true,
    "memoryGiB": 0,
    "name": "ml.geospatial.interactive",
    "supportedImageNames": [
     "sagemaker-geospatial-v1-0"
    ],
    "vcpuNum": 0
   },
   {
    "_defaultOrder": 21,
    "_isFastLaunch": true,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 4,
    "name": "ml.c5.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 22,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.c5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 23,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.c5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 24,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.c5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 25,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 72,
    "name": "ml.c5.9xlarge",
    "vcpuNum": 36
   },
   {
    "_defaultOrder": 26,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 96,
    "name": "ml.c5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 27,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 144,
    "name": "ml.c5.18xlarge",
    "vcpuNum": 72
   },
   {
    "_defaultOrder": 28,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.c5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 29,
    "_isFastLaunch": true,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.g4dn.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 30,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.g4dn.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 31,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.g4dn.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 32,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.g4dn.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 33,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.g4dn.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 34,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.g4dn.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 35,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 61,
    "name": "ml.p3.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 36,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 244,
    "name": "ml.p3.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 37,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 488,
    "name": "ml.p3.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 38,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 768,
    "name": "ml.p3dn.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 39,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.r5.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 40,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.r5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 41,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.r5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 42,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.r5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 43,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.r5.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 44,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.r5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 45,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 512,
    "name": "ml.r5.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 46,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 768,
    "name": "ml.r5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 47,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.g5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 48,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.g5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 49,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.g5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 50,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.g5.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 51,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.g5.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 52,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.g5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 53,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.g5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 54,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 768,
    "name": "ml.g5.48xlarge",
    "vcpuNum": 192
   },
   {
    "_defaultOrder": 55,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 1152,
    "name": "ml.p4d.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 56,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 1152,
    "name": "ml.p4de.24xlarge",
    "vcpuNum": 96
   }
  ],
  "instance_type": "ml.g4dn.xlarge",
  "kernelspec": {
   "display_name": "Python 3 (PyTorch 2.0.0 Python 3.10 GPU Optimized)",
   "language": "python",
   "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-2:429704687514:image/pytorch-2.0.0-gpu-py310"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
